# Build functions

# Copyright 2020-2021 orbea
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

summary=
tab='	'

CWD=$(pwd)
TMP=${TMP:-/tmp/build}

SRCROOT=${SRCROOT:-"$HOME"/src}
GITSRC=${GITSRC:-"$SRCROOT"/git/installed}
TARSRC=${TARSRC:-"$SRCROOT"/tar}

CMAKE_INSTALL=1
DEBUG_RELEASE=
GITPATCHES=

if [ -n "${NOINSTALL:-}" ]; then
  DST="$TMP"/install
else
  DST=''
fi

_build () {
  if [ -r "$1/$1".build ] && [ -x "$1/$1".build ]; then
    printf %s\\n '' "Building $1/$1.build" ''
    log="$1|:|okay"
    BRANCH='' COMMIT='' ./"$1/$1".build || log="$1|:|fail"
    summary="${summary} \"${tab}$log\""
    [ -z "${2:-}" ] || eval "$2=\"\$${2} $1\""
  fi
}

_clone () {
  if [ ! -d "$1/.git" ] || [ ! -r "$1/.git" ] || [ ! -x "$1/.git" ]; then
    _slash () { case "$1" in */) return 1 ;; *) return 0 ;; esac; }
    dir="${1%/"$2"}"
    while ! _slash "$dir"; do
      dir="${dir%/}"
    done
    rm -rf -- "$1"
    mkdir -p -- "$dir"
    git clone "$3" "$1"
    unset -f _slash
  fi
}

_cmake () {
  mkdir -p -- "$TMP"
  cd -- "$TMP"
  src="$1"
  shift
  cmake -GNinja "$@" \
    -DCMAKE_INSTALL_PREFIX="$PKG" \
    -DCMAKE_SKIP_RPATH=TRUE \
    -DCMAKE_BUILD_TYPE="$RELEASE" "$src"/
  "${NINJA:=ninja}"
  [ "$CMAKE_INSTALL" != 1 ] || DESTDIR="$DST" "$NINJA" "$CMAKE_STRIP"
  unset src
}

_die () {
  ret="$1"; shift
  case "$ret" in
    : ) printf %s\\n "$@" >&2; return 0 ;;
    0 ) printf %s\\n "$@" ;;
    * ) printf %s\\n "$@" >&2 ;;
  esac
  exit "$ret"
}

_download () {
  if [ ! -f "$1" ] || [ ! -r "$1" ]; then
    _slash () { case "$1" in */) return 1 ;; *) return 0 ;; esac; }
    dir="${1%/"$2"}"
    while ! _slash "$dir"; do
      dir="${dir%/}"
    done
    rm -f -- "$1"
    mkdir -p -- "$dir"
    wget --content-disposition -P "$dir" "$3"
    unset -f _slash
  fi
}

_exists () {
  r=0; cwd="$(pwd)"
  while [ $# -gt 0 ]; do
    v=1; arg="$1"; shift
    case "$arg" in
      ''|*/ )
        :
      ;;
      /* )
        if [ -f "$arg" ] && [ -x "$arg" ]; then
          printf %s\\n "$arg"
          v=0
        fi
      ;;
      ./* )
        if [ -f "$arg" ] && [ -x "$arg" ]; then
          pre="$(cd -- "${arg%%/*}/" && pwd)"
          printf %s\\n "${pre%/}/$arg"
          v=0
        fi
      ;;
      */* )
        if [ -f "$arg" ] && [ -x "$arg" ]; then
          printf %s\\n "$(cd -- "${arg%%/*}/.." && pwd)/$arg"
          v=0
        fi
      ;;
      * )
        if [ -n "${PATH+x}" ]; then
          p=":${PATH:-$cwd}"
          while [ "$p" != "${p#*:}" ] && [ -n "${p#*:}" ]; do
            p="${p#*:}"; x="${p%%:*}"; z="${x:-$cwd}"; d="${z%/}/$arg"
            if [ -f "$d" ] && [ -x "$d" ]; then
              case "$d" in
                /* ) : ;;
                ./* ) pre="$(cd -- "${d%/*}/" && pwd)"; d="${pre%/}/$d" ;;
                * ) d="$(cd -- "${d%/*}/" && pwd)/$arg" ;;
              esac
              printf %s\\n "$d"
              v=0
              break
            fi
          done
        fi
      ;;
    esac
  [ $v = 0 ] || r=1
  done
  return $r
}

_flags () {
  if [ "${DEBUG:=0}" != 0 ]; then
    DEBUG=1
    BLDFLAGS="${BLDFLAGS:--O0 -pipe}"
    case "${1:-}" in
      cmake )
        CMAKE_STRIP='install'
        RELEASE="${DEBUG_RELEASE:-Debug}"
      ;;
      meson )
        NDEBUG=false
        RELEASE="${DEBUG_RELEASE:-debug}"
      ;;
      * )
        BLDFLAGS="${BLDFLAGS} -g"
      ;;
    esac
  else
    BLDFLAGS="${BLDFLAGS:--O2 -pipe}"
    case "${1:-}" in
      cmake )
        BLDFLAGS="${BLDFLAGS} -DNDEBUG"
        CMAKE_STRIP='install/strip'
        RELEASE=None
      ;;
      meson )
        NDEBUG=true
        RELEASE=plain
      ;;
    esac
  fi
}

_git () {
  _clone "$1" "$2" "$3"
  _git_update "$4" "$1" "$5" "$6" "${7:-}"
  [ "$2" != "${PRGNAM:?}" ] || _git_version
}

_git_update () {
  rm -rf -- "$1"
  cd -- "$2" || return 1
  git reset --hard origin/"$3"
  git clean -xdff
  git checkout "$3"
  sleep 1
  [ -n "${NOUPDATE:=}" ] || git pull
  [ -z "$4" ] || git checkout "$4"
  for patch in $(printf %s "$GITPATCHES"); do
    git apply -3 "$CWD/$patch"
  done
  if [ -n "${5:-}" ]; then
    git submodule foreach --recursive git clean -xdff
    git submodule foreach --recursive git reset --hard
    [ -n "${NOUPDATE}" ] || git submodule update --init --recursive
  fi
}

_git_version () {
  HEAD="$(git rev-parse --short HEAD)"
  DATE="$(git show -s --format=%cd --date=format:%Y.%m.%d)"
  VERSION="${DATE}_$HEAD"
  : "$VERSION"
}

_install () {
  docdir="$3"/share/doc/"$1"
  srcdir="$4"
  mkdir -p -- "$DST$docdir"
  printf %s\\n "$1-$2" > "$DST$docdir/$1".version
  cat -- "$CWD/$1".build > "$DST$docdir/$1".build
  shift 4
  for f do
    if [ ! -e "$srcdir/$f" ]; then
      _die : "WARNING: File '$f' not found"
    elif [ -e "$DST$docdir/${f#*/}" ]; then
      _die : "WARNING: File '$f' already installed"
    elif [ ! -s "$srcdir/$f" ]; then
      _die : "WARNING: Zero length file '$f'"
    else
      cp -p -- "$srcdir/$f" "$DST$docdir/"
    fi
  done
  unset docdir srcdir
}

_install_strip () {
  _strip "$3"
  _install "$@"
}

_make () {
  mkdir -p -- "$TMP"
  cd -- "$TMP"
  target="${1:-install}"
  shift
  make "$target" -f "$@"
  unset target
}

_meson () {
  out="$1"
  shift
  meson "$@" \
    --prefix="$PKG" \
    -Dstrip=$NDEBUG \
    -Db_ndebug=$NDEBUG \
    -Dbuildtype=$RELEASE \
    "$out"
  "${NINJA:=ninja}" -C "$out"
  DESTDIR="$DST" "$NINJA" -C "$out" install
  unset out
}

_strip () {
  [ "${DEBUG:-0}" = 0 ] || return 0
  case "$DST$1" in
    -* ) f="./$DST$1" ;;
    * ) f="$DST$1" ;;
  esac
  find "$f" -print0 | xargs -0 file | grep -e executable -e 'shared object' |
    grep ELF | cut -f 1 -d : | xargs strip 2> /dev/null || :
  unset f
}

_summary () {
  eval "set -- $summary"
  printf %s\\n '' 'Summary:' ''
  printf %s\\n "$@" | column -t -o ' ' -s '|'
  printf %s\\n ''
}

_summary2 () {
  { [ -f "$2/${1}_summary" ] && [ -r "$2/${1}_summary" ]; } || return 0
  printf %s\\n "Summary for $1:"
  cat -- "$2/${1}"_summary
}
